package com.fm.common.net.baseCoroutine.exception

import android.view.View
import com.fm.common.net.baseCoroutine.SafeCoroutineScope
import com.fm.common.net.baseCoroutine.UI
import kotlinx.coroutines.CompletionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlin.coroutines.Continuation
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.CoroutineContext

/**
 * @CreateData:     2020/12/22
 * @Author:         lyy
 * @Description:    类描述
 */

// 在 Android View 中使用的 Job，能够在 View 的生命周期内自动 Disposable
fun View.autoDispose(job: Job) {
    val listener = ViewListener(this, job)
    this.addOnAttachStateChangeListener(listener)
}

// 在 Android View 中创建 autoDisposeScope，支持主线程运行、异常处理、Job 能够在 View 的生命周期内自动 Disposable
val View.autoDisposeScope: CoroutineScope
    get() {
        return SafeCoroutineScope(UI + ViewAutoDisposeInterceptorImpl(this))
    }

private class ViewListener(
    private val view: View,
    private val job: Job
) : View.OnAttachStateChangeListener,
    CompletionHandler {
    override fun onViewDetachedFromWindow(v: View) {
        view.removeOnAttachStateChangeListener(this)
        job.cancel()
    }

    override fun onViewAttachedToWindow(v: View) {
    }

    override fun invoke(cause: Throwable?) {
        view.removeOnAttachStateChangeListener(this)
        job.cancel()
    }
}

private class ViewAutoDisposeInterceptorImpl(
    private val view: View
) : ContinuationInterceptor {
    override val key: CoroutineContext.Key<*>
        get() = ContinuationInterceptor

    override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> {

        continuation.context[Job]?.let {
            view.autoDispose(it)
        }

        return continuation
    }
}